﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

using mvcForum.Core;
using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Events;
using mvcForum.Core.Interfaces.Data;
using mvcForum.Core.Specifications;
using mvcForum.Web.Controllers;
using mvcForum.Web.Extensions;
using mvcForum.Web.Helpers;
using mvcForum.Web.ViewModels;
using mvcForum.Web.Interfaces;
using mvcForum.Core.Interfaces.Events;

namespace mvcForum.Web.Areas.Forum.Controllers {

	public class ModerateController : ThemedForumBaseController {
		private readonly IConfiguration config;
		private readonly IEventPublisher eventPublisher;
		private readonly IBoardRepository boardRepo;
		private readonly IForumRepository forumRepo;
		private readonly IRepository<PostReport> prRepo;
		private readonly ITopicRepository topicRepo;

		#region Constructors
		public ModerateController(IWebUserProvider userProvider, IContext context, IConfiguration config, IEventPublisher eventPublisher, IBoardRepository boardRepo, IForumRepository forumRepo, ITopicRepository topicRepo)
			: base(userProvider, context) {

			this.config = config;
			this.eventPublisher = eventPublisher;
			this.boardRepo = boardRepo;
			this.forumRepo = forumRepo;
			this.topicRepo = topicRepo;
			this.prRepo = this.context.GetRepository<PostReport>();
		}
		#endregion

		public ActionResult Index(Int32? id, Int32? page) {
			ModerateViewModel model = new ModerateViewModel();

			IEnumerable<Board> allActiveBoards = this.boardRepo.ReadManyOptimized(new BoardSpecifications.Enabled());
			// Get the first board in the returned list.
			Board board = allActiveBoards.First();
			// We need to list all the forums the user has moderator access to.
			List<Core.Forum> accessibleForums = new List<Core.Forum>();
			// Let's get all the categories of the board!
			foreach (Category cat in board.Categories) {
				// And let's run through all the forums.
				foreach (Core.Forum forum in cat.Forums.Where(f => !f.ParentForumId.HasValue)) {
					GetAccessibleForums(forum, accessibleForums);
				}
			}
			// Any accessible forums?
			if (accessibleForums.Count == 0) {
				// Ups, the user does not have moderator access to any forum!
				TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForums"));

				return new HttpStatusCodeResult(403);
				// Let's go to the "no access" page!
				return RedirectToRoute("NoAccess");
			}
			model.AccessibleForums = accessibleForums.Select(f => new ForumViewModel(f, this.config.TopicsPerPage, this.config.AuthorNameSetting)).OrderBy(vm => vm.Name);

			if (id.HasValue) {
				Int32 pageIndex = 1;
				if (page.HasValue && page.Value > 0) {
					pageIndex = page.Value;
				}

				Core.Forum forum = this.forumRepo.ReadOneOptimized(new ForumSpecifications.ById(id.Value));
				if (forum != null && !forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}
				if (forum != null) {
					model.SelectedForum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);
					Int32 count = forum.Topics.Count;
					model.SelectedForum.Paging = new PagingModel {
						ActualCount = count,
						Count = count,
						Page = pageIndex,
						Pages = (Int32)Math.Ceiling((Decimal)count / (Decimal)this.config.TopicsPerPage)
					};
					model.SelectedForum.Topics = forum.Topics
											.Where(t => t.TypeValue == (Int32)TopicType.Announcement)
											.OrderByDescending(t => t.LastPosted)
											.Concat(
												forum.Topics.Where(t => t.TypeValue == (Int32)TopicType.Sticky)
												.OrderByDescending(t => t.LastPosted)
												.Concat(
													forum.Topics.Where(t => t.TypeValue == (Int32)TopicType.Regular)
													.OrderByDescending(t => t.LastPosted)
												)
											)
											.Skip((pageIndex - 1) * this.config.TopicsPerPage)
											.Take(this.config.TopicsPerPage)
											.Select(x => new TopicViewModel(x, new MessageViewModel[] { }, x.PostCount, this.config.MessagesPerPage, true, this.config.AllowQuickReply, this.config.AuthorNameSetting));
				}
			}

			// TODO: put all the info in the model!!

			return View(model);
		}

		[HttpPost]
		public ActionResult Execute(Int32 id, Int32[] topics, String action) {
			switch (action.ToLower()) {
				case "delete":
					return this.Redirect(String.Format("/forum/moderate/delete/{0}?{1}", id, String.Join("&", topics.Select(t => String.Format("topics={0}", t)))));
				case "move":
					return this.Redirect(String.Format("/forum/moderate/move/{0}?{1}", id, String.Join("&", topics.Select(t => String.Format("topics={0}", t)))));
				case "merge":
					return this.Redirect(String.Format("/forum/moderate/merge/{0}?{1}", id, String.Join("&", topics.Select(t => String.Format("topics={0}", t)))));
				case "split":
					return this.RedirectToAction("split", new { id = id, topicId = topics.First() });
				//return this.Redirect(String.Format("/forum/moderate/split/{0}?{1}", id, topics.Select(t => String.Format("topicId={0}", t).First())));
				default:
					// TODO: Ups!
					return new HttpStatusCodeResult(404);
			}
		}

		#region Merge
		public ActionResult Merge(Int32 id, Int32[] topics) {
			if (topics != null && topics.Length > 0) {
				Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
				if (topics.Length < 2) {
					TempData.Add("Feedback", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("Merge.MissingTopics"));
					return this.RedirectToAction("index", new { id = id });
				}
				if (!forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}
				MergeViewModel model = new MergeViewModel();
				model.Forum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);
				model.Topics = forum.Topics.Where(t => topics.Contains(t.Id)).Select(t => new TopicViewModel(t, new List<MessageViewModel>(), 0, this.config.MessagesPerPage, this.config.ShowDeletedMessages, this.config.AllowQuickReply, this.config.AuthorNameSetting));
				if (model.Topics.Count() < 2) {
					TempData.Add("Feedback", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("Merge.MissingTopics"));
					return this.RedirectToAction("index", new { id = id });
				}
				return View(model);
			}
			return this.RedirectToAction("Index", new { id = id });
		}

		[HttpPost]
		public ActionResult Merge(Int32 id, Int32[] topics, Boolean confirm) {
			if (topics != null && topics.Length > 0) {
				Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
				if (!forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}
				IEnumerable<Topic> tops = forum.Topics.Where(t => topics.Contains(t.Id)).OrderBy(t => t.Posted);
				IEnumerable<Post> posts = tops.SelectMany(t => t.Posts).OrderBy(p => p.Posted);

				Topic newTopic = tops.First();

				Int32 index = 0;
				foreach (Post post in posts) {
					post.Position = index;
					post.Topic = newTopic;
					index++;
				}

				this.Context.SaveChanges();

				this.eventPublisher.Publish<TopicMergedEvent>(new TopicMergedEvent { ForumId = newTopic.ForumId, TopicId = newTopic.Id });

				Dictionary<Int32, TopicFlag> flags = new Dictionary<Int32, TopicFlag>();
				foreach (Topic topic in tops.OrderByDescending(t => t.Posted).Take(tops.Count() - 1)) {
					flags.Add(topic.Id, topic.Flag);
					topic.SetFlag(TopicFlag.Deleted);
				}

				this.Context.SaveChanges();

				// TODO: One event for all topics!!..
				foreach (Topic topic in tops.OrderByDescending(t => t.Posted).Take(tops.Count() - 1)) {
					this.eventPublisher.Publish<TopicFlagUpdatedEvent>(new TopicFlagUpdatedEvent { OriginalFlag = flags[topic.Id], TopicId = topic.Id, ForumRelativeURL = Url.RouteUrl("ShowForum", new { id = topic.Forum.Id, title = topic.Forum.Name.ToSlug(), area = "forum" }) });
				}
			}

			return this.RedirectToAction("index", new { id = id });
		}
		#endregion

		#region Move
		public ActionResult Move(Int32 id, Int32[] topics) {
			if (topics != null && topics.Length > 0) {
				Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
				if (!forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}

				MoveViewModel model = new MoveViewModel();
				model.Forum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);

				// TODO: can not move: deleted, quarantined and moved!
				model.Topics = forum.Topics.AsQueryable().Where(t => topics.Contains(t.Id)).Where(new TopicSpecifications.Visible().IsSatisfied).Select(t => new TopicViewModel(t, new List<MessageViewModel>(), 0, this.config.MessagesPerPage, false, this.config.AllowQuickReply, this.config.AuthorNameSetting));

				return View(model);
			}

			return this.RedirectToAction("Index", new { id = id });
		}

		[HttpPost]
		public ActionResult Move(Int32 id, Int32 destinationId, Int32[] topics, Boolean? leaveTopic) {
			if (topics != null && topics.Length > 0) {
				Core.Forum sourceForum = this.Context.GetRepository<Core.Forum>().Read(id);
				Core.Forum destinationForum = this.Context.GetRepository<Core.Forum>().Read(destinationId);
				if (!sourceForum.HasAccess(AccessFlag.Moderator) || !destinationForum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = sourceForum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}

				List<Topic> tops = new List<Topic>(sourceForum.Topics.Where(t => topics.Contains(t.Id)));
				Boolean createProxy = leaveTopic.HasValue && leaveTopic.Value;
				foreach (Topic topic in tops) {
					topic.Forum = destinationForum;
					if (createProxy) {
						Topic proxy = new Topic {
							Author = topic.Author,
							AuthorId = topic.AuthorId,
							Title = topic.Title,
							AuthorName = topic.Author.Name,
							Forum = sourceForum,
							ForumId = sourceForum.Id,
							OriginalTopic = topic,
							OriginalTopicId = topic.Id,
							Posted = topic.Posted,
							LastPosted = topic.LastPosted,
							Type = TopicType.Regular,
							PostCount = 0,
							SpamReporters = 0,
							SpamScore = 0,
							ViewCount = 0
						};
						proxy.SetFlag(TopicFlag.Moved);

						this.topicRepo.Create(proxy);

						Post post = new Post(proxy.Author, proxy, proxy.Title, "Moved ", topic.Posts.OrderBy(p => p.Posted).First().IP);
						post.Position = 0;
						post.ModeratorChanged = false;
						this.Context.GetRepository<Post>().Create(post);
					}
				}

				this.Context.SaveChanges();

				foreach (Topic topic in tops) {
					// TODO: One event?!
					this.eventPublisher.Publish<TopicMovedEvent>(new TopicMovedEvent { SourceForumId = sourceForum.Id, DestinationForumId = destinationForum.Id, TopicId = topic.Id });
				}
			}

			return this.RedirectToAction("index", new { id = id });
		}
		#endregion

		#region Delete
		public ActionResult Delete(Int32 id, Int32[] topics) {
			if (topics != null && topics.Length > 0) {
				Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
				if (!forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}
				DeleteViewModel model = new DeleteViewModel();
				model.Forum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);
				model.Topics = forum.Topics.Where(t => topics.Contains(t.Id) && t.FlagValue != (Int32)TopicFlag.Deleted).Select(t => new TopicViewModel(t, new List<MessageViewModel>(), 0, this.config.MessagesPerPage, false, this.config.AllowQuickReply, this.config.AuthorNameSetting));
				if (model.Topics.Count() < 1) {
					return this.RedirectToAction("index", new { id = id });
				}
				return View(model);
			}
			return this.RedirectToAction("index", new { id = id });
		}

		[HttpPost]
		public ActionResult Delete(Int32 id, Int32[] topics, Boolean confirm) {
			if (topics != null && topics.Length > 0) {
				Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
				if (!forum.HasAccess(AccessFlag.Moderator)) {
					// Ups, the user does not have moderator access to the forum!
					TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
					// Let's go to the "no access" page!
					return RedirectToRoute("NoAccess");
				}
				IEnumerable<Topic> tops = forum.Topics.Where(t => topics.Contains(t.Id)).ToList();

				// TODO: Delete moved topics !??!

				TopicFlag originalFlag;
				foreach (Topic top in tops) {
					Topic originalTopic = this.topicRepo.ReadOne(new TopicSpecifications.MovedTopic(top));
					// Is this topic actually a "moved" topic?
					if (originalTopic != null) {
						// Yes, then we better get rid of the original topic!
						originalFlag = originalTopic.Flag;
						originalTopic.SetFlag(TopicFlag.Deleted);

						this.Context.SaveChanges();

						this.eventPublisher.Publish(new TopicFlagUpdatedEvent { TopicId = originalTopic.Id, OriginalFlag = originalFlag, ForumRelativeURL = Url.RouteUrl("ShowForum", new { id = forum.Id, title = forum.Name.ToSlug(), area = "forum" }) });

						IRepository<Post> postRepo = this.Context.GetRepository<Post>();
						foreach (Post post in originalTopic.Posts) {
							postRepo.Delete(post);
						}

						this.topicRepo.Delete(originalTopic);

						this.Context.SaveChanges();
					}
					originalFlag = top.Flag;
					top.SetFlag(TopicFlag.Deleted);

					this.Context.SaveChanges();

					this.eventPublisher.Publish(new TopicFlagUpdatedEvent { TopicId = top.Id, OriginalFlag = originalFlag, ForumRelativeURL = Url.RouteUrl("ShowForum", new { id = forum.Id, title = forum.Name.ToSlug(), area = "forum" }) });
				}
			}

			return this.RedirectToAction("index", new { id = id });
		}
		#endregion

		#region Split
		public ActionResult Split(Int32 id, Int32 topicId) {
			Core.Forum forum = this.Context.GetRepository<Core.Forum>().Read(id);
			if (!forum.HasAccess(AccessFlag.Moderator)) {
				// Ups, the user does not have moderator access to the forum!
				TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
				// Let's go to the "no access" page!
				return RedirectToRoute("NoAccess");
			}
			Topic topic = forum.Topics.Where(t => t.Id == topicId).First();
			if (topic == null) {
				return this.RedirectToAction("index", new { id = id });
			}

			SplitViewModel model = new SplitViewModel();
			model.Forum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);
			model.Topic = new TopicViewModel(topic, topic.Posts.Select(p => new MessageViewModel(p, this.config.AuthorNameSetting)), topic.Posts.Count, Int32.MaxValue, false, this.config.AllowQuickReply, this.config.AuthorNameSetting);
			model.OriginalTopicTitle = topic.Title;
			return View(model);
		}

		[HttpPost]
		public ActionResult Split(SplitViewModel model) {
			Core.Forum forum = this.forumRepo.Read(model.ForumId);
			if (!forum.HasAccess(AccessFlag.Moderator)) {
				// Ups, the user does not have moderator access to the forum!
				TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = forum.Name }));
				// Let's go to the "no access" page!
				return RedirectToRoute("NoAccess");
			}
			Topic topic = forum.Topics.Where(t => t.Id == model.TopicId).First();
			if (topic == null) {
				return this.RedirectToAction("index", new { id = model.ForumId });
			}

			if (ModelState.IsValid) {
				IEnumerable<Post> posts = topic.Posts.Where(p => model.PostId.Contains(p.Id)).OrderBy(p => p.Posted);
				if (posts.Count() == 0) {
					return this.RedirectToAction("index", new { id = model.ForumId });
				}

				if (posts.Where(p => p.Position == 0).Any()) {
					// We have the original topic in this selection, let's create the new one
					// of the reverse selection!
					posts = topic.Posts.Where(p => !posts.Select(pr => pr.Id).Contains(p.Id));
				}

				// Let's get the topic post!
				Post topicPost = posts.OrderBy(p => p.Posted).First();
				// And get rid of the topic post in the list of posts!
				posts = posts.Where(p => p.Id != topicPost.Id).OrderBy(p => p.Posted);
				// Create the new topic!
				Core.Topic newTopic = new Topic(topicPost.Author, forum, model.NewTopicTitle.Replace("<", "&lt;"));
				newTopic.Posted = topicPost.Posted;
				newTopic.SetFlag(TopicFlag.None);
				newTopic.Type = TopicType.Regular;
				this.topicRepo.Create(newTopic);

				// And move the topic post to the new topic!
				topicPost.Topic = newTopic;
				topicPost.Indent = 0;
				topicPost.ReplyToPostId = null;
				topicPost.Position = 0;
				this.context.SaveChanges();

				Int32 index = 1;
				// Let's move the posts into the new topic!
				foreach (Post post in posts) {
					post.Topic = newTopic;
					post.Position = index;
					index++;
				}

				// Position 0 is already gone, so no need to -1
				newTopic.PostCount = posts.Visible(this.config).Count();
				this.context.SaveChanges();

				// Get the original topic!
				topic = this.topicRepo.Read(model.TopicId);
				index = 0;
				// Let's re-position all posts!
				foreach (Post post in topic.Posts) {
					post.Position = index;
					index++;
				}

				// Let's get rid of position = 0, -1 for that!
				topic.PostCount = topic.Posts.Visible(this.config).Count() - 1;
				this.context.SaveChanges();

				this.eventPublisher.Publish<TopicSplitEvent>(new TopicSplitEvent { OriginalTopicId = topic.Id, NewTopicId = newTopic.Id });

				//String forumUrl = Url.RouteUrl("ShowForum", new { id = forum.Id, area = "forum", title = forum.Name.ToSlug() });
				//// Topic updated..! We better inform whoever is listening!
				//this.eventPublisher.Publish<TopicUpdatedEvent>(new TopicUpdatedEvent { ForumId = forum.Id, TopicId = topic.Id, UserAgent = "" });
				//// New topic, let's throw that event, so search etc. can catch it!
				//this.eventPublisher.Publish<NewTopicEvent>(new NewTopicEvent { ForumId = forum.Id, TopicId = newTopic.Id, ForumRelativeURL = forumUrl, UserAgent = ""});

				//String newTopicUrl = Url.RouteUrl("ShowTopic", new { id = newTopic.Id, area = "forum", title = newTopic.Title.ToSlug() });
				//String oldTopicUrl = Url.RouteUrl("ShowTopic", new { id = topic.Id, area = "forum", title = topic.Title.ToSlug() });
				//this.eventPublisher.Publish<NewPostEvent>(new NewPostEvent { ForumId = forum.Id, PostId = newTopic.Posts.OrderByDescending(p => p.Posted).First().Id, TopicId = newTopic.Id, UserAgent = "", TopicRelativeURL = newTopicUrl });
				//this.eventPublisher.Publish<NewPostEvent>(new NewPostEvent { ForumId = forum.Id, PostId = topic.Posts.OrderByDescending(p => p.Posted).First().Id, TopicId = topic.Id, UserAgent = "", TopicRelativeURL = oldTopicUrl });

				return this.RedirectToAction("index", new { id = model.ForumId });
			}

			model.Forum = new ForumViewModel(forum, this.config.TopicsPerPage, this.config.AuthorNameSetting);
			model.Topic = new TopicViewModel(topic, new List<MessageViewModel>(), topic.Posts.Count, Int32.MaxValue, false, this.config.AllowQuickReply, this.config.AuthorNameSetting);
			return View(model);
		}
		#endregion

		public ActionResult Topic(Int32 id, Int32? page) {
			Topic topic = this.topicRepo.ReadOneOptimizedWithPosts(new TopicSpecifications.ById(id));
			if (topic == null) {
				return new HttpStatusCodeResult(404);
			}
			if (!topic.Forum.HasAccess(AccessFlag.Moderator)) {
				// Ups, the user does not have moderator access to the forum!
				TempData.Add("Reason", ForumHelper.GetString<mvcForum.Web.ForumConfigurator>("NoAccess.ModeratorForum", new { Name = topic.Forum.Name }));
				// Let's go to the "no access" page!
				return RedirectToRoute("NoAccess");
			}
			Int32 pageIndex = 1;
			if (page.HasValue && page.Value > 0) {
				pageIndex = page.Value;
			}

			TopicViewModel model = new TopicViewModel(
												topic,
												topic.Posts.OrderBy(p => p.Posted)
													.Skip((pageIndex - 1) * this.config.MessagesPerPage)
													.Take(this.config.MessagesPerPage)
													.Select(p => new MessageViewModel(p, this.config.AuthorNameSetting)),
												topic.Posts.Count,
												this.config.MessagesPerPage,
												true,
												this.config.AllowQuickReply,
												this.config.AuthorNameSetting
											);
			model.Path = new Dictionary<String, String> {
					{ Url.Action("index", "moderate", new { id = topic.Forum.Id }), ForumHelper.GetString("Moderate.TitleMain") },
					{ Url.Action("topic", "moderate", new { id = topic.Id }), topic.Title } };

			return View(model);
		}

		public ActionResult ReportList() {
			IEnumerable<PostReport> reports = this.prRepo.ReadMany(new PostReportSpecifications.NotResolved());
			List<PostReport> accessibleReports = new List<PostReport>();
			foreach (PostReport report in reports) {
				if (report.Post.Topic.Forum.HasAccess(AccessFlag.Moderator)) {
					accessibleReports.Add(report);
				}
			}

			return View(accessibleReports.Select(r => new PostReportViewModel(r)).OrderBy(r => r.Timestamp));
		}

		#region Report
		public ActionResult Report(Int32 id) {
			PostReport report = this.prRepo.Read(id);
			return View(new PostReportViewModel(report));
		}

		[HttpPost]
		public ActionResult Report(PostReportViewModel model) {
			if (ModelState.IsValid) {
				PostReport pr = this.prRepo.Read(model.Id);
				pr.Resolved = model.Resolved;
				if (pr.Resolved) {
					pr.ResolvedBy = this.ActiveUser;
					pr.ResolvedTimestamp = DateTime.UtcNow;
				}

				if (pr.Post.Position == 0) {
					//pr.Post.Topic.RemoveFlag(pr.Post.Topic.Flag);
					pr.Post.Topic.SetFlag(model.TopicFlag);
					pr.Post.Topic.Type = model.TopicType;
					pr.Post.Update(this.ActiveUser, model.Title, model.Content, model.ChangeReason);
				}
				else {
					//pr.Post.RemoveFlag(pr.Post.Flag);
					pr.Post.SetFlag(model.PostFlag);
					pr.Post.Update(this.ActiveUser, model.Subject, model.Content, model.ChangeReason);
				}

				this.Context.SaveChanges();

				this.eventPublisher.Publish(new PostReportResolvedEvent { PostReportId = pr.Id });

				return RedirectToAction("ReportList", "Moderate");
			}
			else {
				PostReport pr = this.prRepo.Read(model.Id);
				model.Populate(pr);
			}
			return View(model);
		}
		#endregion

		[NonAction]
		private void GetAccessibleForums(Core.Forum forum, List<Core.Forum> accessibleForums) {
			if (forum.HasAccess(AccessFlag.Moderator)) {
				accessibleForums.Add(forum);
			}
			foreach (Core.Forum subForum in forum.SubForums) {
				GetAccessibleForums(subForum, accessibleForums);
			}
		}
	}
}